using System;
using System.IO;
using System.Reflection;
using NUnit.Framework;
using ODX.Core;
using ODX.LazyUnitTester;

namespace Offline
{
    [Table]
    public abstract class Person : Entity
    {
        public abstract string Name { get; set;}
        public abstract int Age { get; set;}
        public abstract IEntityList<Pet> Pets { get; }
    }

    [Table("Pet")]
    public abstract class Pet : Entity
    {
        public abstract string Name { get; set;}
        public abstract Person Master { get; set; }
    }

    [TestFixture]
    public class C07_Offline
    {
        [TestBody]
        static void Main()
        {
            const string fileName = "pets.xml";
            const string offlineFileName = "pets.bin";

            Init(fileName);
            CreateReplica(fileName, offlineFileName);
            ModifyReplica(offlineFileName);
            ModifyOnline(fileName);
            MergeReplica(fileName, offlineFileName);

            Session session = new Session(
                new XmlDataProvider(fileName),
                Assembly.GetExecutingAssembly());

            Person john = session.SelectOne<Person>("Name = ?", null, "John");

            LUT.WriteLine("Now {0} is {1}. He masters", john.Name, john.Age);
            foreach (Pet pet in john.Pets)
                LUT.WriteLine("\t{0}", pet.Name);

            session.Combine(session);
        }

        private static void MergeReplica(string fileName, string offlineFileName)
        {
            // Create "connected" session.
            Session session = new Session(
                new XmlDataProvider(fileName),
                Assembly.GetExecutingAssembly());

            // Load offline data in connected session.
            session.LoadFromFile(offlineFileName);

            // Save replica to the online data source.
            session.Save();
        }

        private static void ModifyOnline(string fileName)
        {
            // Create "connected" session
            Session session = new Session(
                new XmlDataProvider(fileName),
                Assembly.GetExecutingAssembly());

            // Find and modify John 
            Person john = session.SelectOne<Person>("Name = ?", null, "John");

            john.Age--;

            Pet rat = session.Create<Pet>();
            rat.Name = "Alice";
            rat.Master = john;
            session.Save();
        }

        private static void ModifyReplica(string offlineFileName)
        {
            // Create "disconnected" session.
            Session offlineSession = new Session(Assembly.GetExecutingAssembly());

            // Load Replica data into the session.
            offlineSession.LoadFromFile(offlineFileName);

            // Select John
            Person offlineJohn = offlineSession.SelectOne<Person>(
                "Name = ?", null, "John");

            // Perform data modifications
            offlineJohn.Age++;
            Pet dog = offlineSession.Create<Pet>();
            dog.Name = "Beethoven";
            dog.Master = offlineJohn;

            offlineSession.SaveToFile(offlineFileName);
        }

        private static void Init(string fileName)
        {
            if (File.Exists(fileName))
                File.Delete(fileName);

            // Create "connected" session
            Session session = new Session(new XmlDataProvider(fileName));
            session.RegisterAssembly(Assembly.GetExecutingAssembly());
            session.Prepare();

            // Populate connected sesson with some data
            Person john = session.Create<Person>();
            john.Name = "John";
            john.Age = 23;

            Pet cat = session.Create<Pet>();
            cat.Name = "Molly";
            cat.Master = john;

            // Commit changes to the data source.
            session.Save();
        }

        private static void CreateReplica(string xmlFileName, string offlineFileName)
        {
            if (File.Exists(offlineFileName))
                File.Delete(offlineFileName);

            // Create "connected" session
            Session connectedSession = new Session(
                new XmlDataProvider(xmlFileName),
                Assembly.GetExecutingAssembly());

            // Load all required data
            Person john = connectedSession.SelectOne<Person>(
                "Name = ?", null, "John");

            // This forces load of children
            john.Pets.Count.ToString();

            // Save connected session in format openable offline.
            connectedSession.SaveToFile(offlineFileName);
        }

        [Test]
        public void Test()
        {
            LUT.Execute(Main);
        }
    }
}
